package com.drpclub.gamebackend.service;

import cn.hutool.core.lang.UUID;
import com.drpclub.gamebackend.bean.Content;
import com.drpclub.gamebackend.bean.ContentBody;
import com.drpclub.gamebackend.common.constant.Const;
import com.drpclub.gamebackend.dao.ResourceDao;
import com.drpclub.gamebackend.exception.IgnoreException;
import com.drpclub.gamebackend.repository.ResourceRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.redis.core.ReactiveHashOperations;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static org.springframework.data.domain.Sort.Direction.ASC;
import static org.springframework.data.domain.Sort.Direction.DESC;

/**
 * @author ：drp
 * @date ：Created in 2020/5/8 17:43
 */
@Slf4j
@Service
public class RecommendResourceService {
    @Resource
    private ResourceRepository resRep;

    @Resource
    private ReactiveStringRedisTemplate reactiveStringRedisTemplate;

    /**
     * 获取轮播图
     */
    public List<ResourceDao> getCarousel(int page, int size, String type) {
        PageRequest pageRequest = PageRequest.of(page, size, DESC, "heat");
        if (type == null || type.equals("")) {
            return resRep.findAllByIsValueAndIsPublish(pageRequest, 1, 1).toList();
        } else {
            return resRep.findAllByTypeIsLikeAndIsValueAndIsPublish(pageRequest, type, 1, 1).toList();
        }
    }

    /**
     * 获取指定类型的内容
     */
    public List<ContentBody> getContent(int page, int size, List<String> types) {
        return types.stream()
                .map(type -> new ContentBody(type, getContentBody(page, size, type)))
                .collect(Collectors.toList());
    }

    private List<Content> getContentBody(int page, int size, String type) {

        return IntStream.rangeClosed(0, 1).boxed().map(i -> {
            //create page request
            PageRequest pageReq = PageRequest.of(page + i, size, ASC, "heat");
            //search
            List<ResourceDao> res;
            if (type != null && !type.equals("")) {
                res = resRep.findAllByTypeIsLikeAndIsValueAndIsPublish(pageReq, type, 1, 1).toList();
            } else {
                Page<ResourceDao> details = resRep.findAllByIsValueAndIsPublish(pageReq, 1, 1);
                res = details.toList();
            }
            if (res == null || res.size() == 0) {
                throw new IgnoreException("没有更多了");
            }
            return new Content(UUID.fastUUID().toString(true), res);
        }).collect(Collectors.toList());
    }

    public List<Content> getRecommendBody(int size, int page) {
        return getContentBody(page, size, null);
    }

    public int countContentType() {
        return resRep.countType();
    }

    @Transactional(transactionManager = Const.TRANSACTION_MANAGER, rollbackFor = {Exception.class})
    public boolean changeHeat(String contentId, String username, String ip) {
        final ReactiveHashOperations<String, String, String> opsForHash = reactiveStringRedisTemplate.opsForHash();
        username = username != null ? username : ip;

        String cIp = opsForHash.get(contentId, username)
                .timeout(Duration.ofMillis(500))
                .onErrorResume(e -> Mono.just(Const.NOTNULL))
                .block();
        if (cIp != null) {
           return true;
        }

        opsForHash.put(contentId, username, ip)
                .concatWith(reactiveStringRedisTemplate.expire(contentId, Duration.ofHours(1)))
                .subscribe();

        return resRep.updateHeatAddByContentId(contentId) > 0;
    }
}
